package com.u2ds.core.util;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.Format;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * @author Ethan
 * @date 下午3:20:42
 * @email windofdusk@gmail.com
 * 类说明
 */
public class DateUtil {
	public final static String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public final static String DATE_FORMAT_MM__yy = "MM/yy";

    public final static String DATE_FORMAT_yyyy__MM = "yyyy/MM";

    public final static String DATE_FORMAT_MMM_yy = "MMM-yy";

    public static final String DATE_FORMAT_yyyyMM = "yyyyMM";

    public static final String DATE_FORMAT_yyyy__MM__dd = "yyyy-MM-dd";
    
    public static final String DATE_FORMATyyyyMMdd_CHN = "yyyy年MM月dd日";

    public static final String DATE_FORMAT_yyyyMMdd = "yyyyMMdd";

    public static final String DATE_FORMAT_MM_dd_yy = "MM/dd/yy";

    public final static String DATE_FORMAT_yyyy__MM__dd_HH_mm_ss = "yyyy/MM/dd HH:mm:ss";
    
    public final static String DATE_FORMAT_yyyyMMddHHmmssSSS = "yyyyMMddHHmmssSSS";
    
    public final static String DATE_FORMAT_yyyyMMddHHmmss = "yyyyMMddHHmmss";

    public final static long nd = 1000*24*60*60;//一天的毫秒数
    public final static long nh = 1000*60*60;//一小时的毫秒数
    public final static long nm = 1000*60;//一分钟的毫秒数
    public final static long ns = 1000;//一秒钟的毫秒数

    public static List getDisplayMonth(Date time, int monthBefore,
            int monthAfter, SimpleDateFormat format) {
        ArrayList result = new ArrayList();
        Calendar calendar = Calendar.getInstance();
        if (null != time) {
            calendar.setTimeInMillis(time.getTime());
        }
        SimpleDateFormat tmpformat = format;
        if (null == tmpformat) {
            tmpformat = new SimpleDateFormat(DATE_FORMAT_yyyy__MM);
        }
        Calendar calendartmp = Calendar.getInstance();

        for (int i = monthBefore; i <= monthAfter; i++) {
            calendartmp.setTimeInMillis(calendar.getTimeInMillis());
            calendartmp.set(Calendar.DAY_OF_MONTH, 1);
            calendartmp.set(Calendar.HOUR_OF_DAY, 0);
            calendartmp.set(Calendar.MINUTE, 0);
            calendartmp.set(Calendar.SECOND, 0);
            calendartmp.set(Calendar.MILLISECOND, 0);

            calendartmp.add(Calendar.MONTH, i);
            result.add(tmpformat
                    .format(new Date(calendartmp.getTimeInMillis())));
        }
        return result;

    }
    
    public static synchronized long getSysTimeGenerator() {
		Date date = new Date();
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT_yyyyMMddHHmmssSSS);
		return Long.valueOf(formatter.format(date));
	}

    @SuppressWarnings("unchecked")
	public static List getDisplayMonth(Date from, Date to, String pattern) {
        ArrayList result = new ArrayList();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(from);
        Calendar calendarTo = Calendar.getInstance();
        calendarTo.setTime(getMonthLastDay(to));
        if (pattern == null) {
            pattern = DATE_FORMAT_yyyy__MM;
        }
        SimpleDateFormat formatter = new SimpleDateFormat(pattern,
                Locale.ENGLISH);

        while (calendar.before(calendarTo)) {
            result.add(formatter.format(calendar.getTime()));
            calendar.add(Calendar.MONTH, 1);
        }
        return result;

    }

    public static List getDisplayMonth(Date time, int monthBefore,
            int monthAfter) {
        return getDisplayMonth(time, monthBefore, monthAfter, null);
    }

	public static List getDisplayMonth(int monthBefore, int monthAfter) {
        return getDisplayMonth(null, monthBefore, monthAfter);
    }

    public static List getDisplayMonth(int monthBefore, int monthAfter,
            String format) {
        return getDisplayMonth(null, monthBefore, monthAfter,
                new SimpleDateFormat(format, Locale.ENGLISH));
    }

    /**
     * get months based on time, return array length is monthAfter-monthBefore+1 
     * @param time
     * @param monthBefore
     * @param monthAfter
     * @return Date[]
     */
    public static Date[] getMonth(Date time, int monthBefore, int monthAfter) {
        ArrayList result = new ArrayList();
        Calendar calendar = Calendar.getInstance();
        if (null != time) {
            calendar.setTimeInMillis(time.getTime());
        }
        for (int i = monthBefore; i <= monthAfter; i++) {
            Calendar calendartmp = Calendar.getInstance();
            calendartmp.setTimeInMillis(calendar.getTimeInMillis());
            calendartmp.set(Calendar.DAY_OF_MONTH, 1);
            calendartmp.set(Calendar.HOUR_OF_DAY, 0);
            calendartmp.set(Calendar.MINUTE, 0);
            calendartmp.set(Calendar.SECOND, 0);
            calendartmp.set(Calendar.MILLISECOND, 0);
            calendartmp.add(Calendar.MONTH, i);
            result.add(new Date(calendartmp.getTimeInMillis()));
        }
        return (Date[]) (result.toArray(new Date[monthAfter - monthBefore + 1]));
    }

    /**
    * get months based on startMonth and endMonth, return array  
    * @param time
    * @param monthBefore
    * @param monthAfter
    * @return Date[]
    */
    public static Date[] getMonth(Date startMonth, Date endMonth) {
        ArrayList result = new ArrayList();
        Calendar calendar = Calendar.getInstance();
        Calendar calendarEnd = Calendar.getInstance();
        if (null != startMonth) {
            calendar.setTimeInMillis(startMonth.getTime());
        }
        if (null != endMonth) {
            calendarEnd.setTimeInMillis(endMonth.getTime());
        }
        while (!calendar.after(calendarEnd)) {
            result.add(new Date(calendar.getTimeInMillis()));
            calendar.add(Calendar.MONTH, 1);

        }
        return (Date[]) (result.toArray(new Date[result.size()]));
    }

    public static Date getNextMonth(Date time) {
        Calendar calendar = Calendar.getInstance();
        if (null != time) {
            calendar.setTimeInMillis(time.getTime());
        }
        calendar.add(Calendar.MONTH, 1);
        return new Date(calendar.getTimeInMillis());
    }

    public static Date getPreviousMonth(Date time) {
        Calendar calendar = Calendar.getInstance();
        if (null != time) {
            calendar.setTimeInMillis(time.getTime());
        }
        calendar.add(Calendar.MONTH, -1);
        return new Date(calendar.getTimeInMillis());
    }

    public static Date[] getMonth(int monthBefore, int monthAfter) {
        return getMonth(null, monthBefore, monthAfter);
    }

    public static String getCurrentTimeString() {
        java.util.Date now = Calendar.getInstance().getTime();
        Format formatter = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
        return formatter.format(now);
    }
    
    public static String getCurrentTimeStringCH(){
    	java.util.Date now = Calendar.getInstance().getTime();
        Format formatter = new SimpleDateFormat(DATE_FORMAT_yyyy__MM__dd);
        return formatter.format(now);
    }

    public static String formatDate(Date date) {
        if (date == null)
            return null;

        Format formatter = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
        return formatter.format(date);
    }

    /**
     * Format date by the format
     * @param date - the source date
     * @param format - the date format
     *
     * @return the result String
     */
    public static String formatDate(Date date, String format) {
        if (date == null)
            return null;

        Format formatter = new SimpleDateFormat(format);
        return formatter.format(date);
    }

    public static String formatDisplayDate(Date date, String format) {
        if (date == null)
            return null;

        Format formatter = new SimpleDateFormat(format, Locale.ENGLISH);
        return formatter.format(date);
    }

    public static boolean monthInRange(Date current, Date before, Date after) {
        Calendar curr = Calendar.getInstance();
        curr.setTime(current);
        Calendar temp = Calendar.getInstance();
        temp.setTime(before);
        temp.set(Calendar.DAY_OF_MONTH, 1);
        temp.set(Calendar.HOUR_OF_DAY, 0);
        temp.set(Calendar.MINUTE, 0);
        temp.set(Calendar.SECOND, 0);
        if (curr.before(temp)) {
            return false;
        }
        temp.setTime(after);
        temp.add(Calendar.MONTH, 1);
        temp.set(Calendar.DAY_OF_MONTH, 1);
        temp.set(Calendar.HOUR_OF_DAY, 0);
        temp.set(Calendar.MINUTE, 0);
        temp.set(Calendar.SECOND, 0);
        if (curr.after(temp)) {
            return false;
        }
        return true;
    }

    public static boolean monthEquals(Date current, Date compare) {
        Calendar curr = Calendar.getInstance();
        curr.setTime(current);
        Calendar cmp = Calendar.getInstance();
        cmp.setTime(compare);
        int year1 = curr.get(Calendar.YEAR);
        int year2 = cmp.get(Calendar.YEAR);
        int month1 = curr.get(Calendar.MONTH);
        int month2 = cmp.get(Calendar.MONTH);
        return (year1 == year2) && (month1 == month2);
    }

    public static String getMonthRate(Date date, boolean moveIn) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int day = calendar.get(Calendar.DAY_OF_MONTH);

        int daysOfThisMonth = calendar.getActualMaximum(Calendar.DATE);
        double rate;
        if (moveIn) {
            rate = (double) (daysOfThisMonth - day + 1) / daysOfThisMonth;
        } else {
            rate = (double) day / daysOfThisMonth;
        }
        rate = (double) Math.round(rate * 10) / 10;
        return String.valueOf(rate);
    }

    public static String getMonthRate(Date dateIn, Date DateOut) {
        Calendar calIn = Calendar.getInstance();
        calIn.setTime(dateIn);
        Calendar calOut = Calendar.getInstance();
        calOut.setTime(DateOut);
        int day = calOut.get(Calendar.DAY_OF_MONTH)
                - calIn.get(Calendar.DAY_OF_MONTH) + 1;
        int daysOfThisMonth = calIn.getActualMaximum(Calendar.DATE);
        double rate = (double) day / daysOfThisMonth;
        rate = (double) Math.round(rate * 10) / 10;
        return String.valueOf(rate);
    }

    public static Date parse(String dateString, String format) {
        if (null == dateString || dateString.length() == 0) {
            return null;
        }
        DateFormat formatter = new SimpleDateFormat(format);
        return formatter.parse(dateString, new ParsePosition(0));
    }

    public static Date parseInEnglishLocale(String dateString, String format) {
        DateFormat formatter = new SimpleDateFormat(format, Locale.ENGLISH);
        return formatter.parse(dateString, new ParsePosition(0));
    }

    public static Date parseTargetMonth(String dateString) {
        return parse(dateString, DATE_FORMAT_yyyy__MM);
    }

    public static int compareDate(Date first, Date second) {
        Calendar cf = Calendar.getInstance();
        cf.setTime(first);
        Calendar cs = Calendar.getInstance();
        cs.setTime(second);
        if (cf.after(cs)) {
            return 1;
        } else {
            return (cf.before(cs)) ? -1 : 0;
        }
    }

    public static Date getMonthLastDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        if (null != date) {
            calendar.setTime(date);
        }
        calendar.set(Calendar.DAY_OF_MONTH, calendar
                .getActualMaximum(Calendar.DATE));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    public static Date getMonthFirstDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        if (null != date) {
            calendar.setTime(date);
        }
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * @param string
     * @return
     */
    public static String getCurrentTimeString(String pattern) {
        java.util.Date now = Calendar.getInstance().getTime();
        Format formatter = new SimpleDateFormat(pattern);
        return formatter.format(now);
    }
    
    /**
     * @param string
     * @return
     */
    public static String getCurrentTimeString(String pattern,Date date) {
        Format formatter = new SimpleDateFormat(pattern);
        return formatter.format(date);
    }

    /**
         * @param date
         * @param offset
         * @return
         */
    public static Date getMonthByOffset(Date date, int offset) {
        Calendar calendar = Calendar.getInstance();
        if (null != date) {
            calendar.setTime(date);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
        }
        calendar.add(Calendar.MONTH, offset);
        return calendar.getTime();
    }

    /**
     * @param targetMonth
     * @param newTargetMonth
     * @return
     */
    public static int compareMonth(Date first, Date second) {
        Calendar cf = Calendar.getInstance();
        cf.setTime(first);
        Calendar cs = Calendar.getInstance();
        cs.setTime(second);
        int offset = (cs.get(Calendar.YEAR) - cf.get(Calendar.YEAR)) * 12
                + (cs.get(Calendar.MONTH) - cf.get(Calendar.MONTH));
        return offset;
    }

    /**
     * @param currDate
     * @return
     */
    public static int getDaysOfMonth(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.getActualMaximum(Calendar.DATE);
    }

    /**
     * @param mpDate
     * @return
     */
    public static int getDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * @param monthSeq
     * @return
     */
    public static int getDaysOfMonth(Date startMonth, Integer monthSeq) {
        Date month = getMonthByOffset(startMonth, monthSeq.intValue() - 1);
        return getDaysOfMonth(month);
        // return 30;
    }

    public static Date getStartTimeOfDate(Date date) {
        Calendar calendar = getCalendarByDate(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    public static Date getEndTimeOfDate(Date date) {
    	if(NullUtil.isNull(date)){
    		return null;
    	}
        Calendar calendar = getCalendarByDate(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);

        return calendar.getTime();
    }

    private static Calendar getCalendarByDate(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c;
    }

    public static  int getCurrentYear(){
		Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        int year = c.get(Calendar.YEAR);
		return year;
	}

    public static  int getCurrentMonth(){
		Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        int month = c.get(Calendar.MONTH);
		return month;
	}	
    
    public static Date formateDate(Date date , String formate){
    	SimpleDateFormat   sdf = new   SimpleDateFormat(formate);
		String   time= sdf.format(date);
        Date result = date;
        try{
            result = sdf.parse(time);
        }catch (Exception e){
            //do nothing
        }
		return result;
    }
    
    public static Date getCurrentDate(){
    	return new Date();
    }
    
    public static Date addDay(Date date, int days){
    	if(NullUtil.isNull(date)){
    		return null;
    	}
    	Calendar calendar = Calendar.getInstance();
    	calendar.setTime(date);
    	calendar.add(Calendar.DATE, days);
    	if(date instanceof java.sql.Date){
    		return new java.sql.Date(calendar.getTime().getTime());
    	}else{
    		return calendar.getTime();
    	}
    	
    }
    
    public static Date addHours(Date date, Double hours){
    	if(NullUtil.isNull(date)){
    		return null;
    	}
    	if(null == hours){
    		return null;
    	}
    	Calendar calendar = Calendar.getInstance();
    	calendar.setTime(date);
    	calendar.add(Calendar.HOUR_OF_DAY, hours.intValue());
    	if(date instanceof java.sql.Date){
    		return new java.sql.Date(calendar.getTime().getTime());
    	}else{
    		return calendar.getTime();
    	}
    	
    }
    
    public static Date addMinutes(Date date, int minutes){
    	if(NullUtil.isNull(date)){
    		return null;
    	}
    	Calendar calendar = Calendar.getInstance();
    	calendar.setTime(date);
    	calendar.add(Calendar.MINUTE, minutes);
    	if(date instanceof java.sql.Date){
    		return new java.sql.Date(calendar.getTime().getTime());
    	}else{
    		return calendar.getTime();
    	}
    	
    }
    /**
     * 添加月
     * @param date
     * @param month
     * @return
     * lilang 2012-5-18上午10:24:57
     */
    public static Date addMonth(Date date, int month){
    	if(NullUtil.isNull(date)){
    		return null;
    	}
    	Calendar calendar = Calendar.getInstance();
    	calendar.setTime(date);
    	calendar.add(Calendar.MONTH, month);
    	return calendar.getTime();
    }
    
    public static Date getBeginOfADay(Date date){
    	if(NullUtil.isNull(date)){
    		return null;
    	}
    	Date ret = DateUtil.parse(DateUtil.formatDate(date, "yyyy-MM-dd") + " 00:00:00", "yyyy-MM-dd");
    	if(date instanceof java.sql.Date){
    		return new java.sql.Date(ret.getTime());
    	}else{
    		return ret;
    	}
    }
    /**
     * 获取当前日期，YMD格式
     * @return
     * @author wenping.rong
     */
    public static Date getNowYmd(){
		return getYmd(new Date());
    }

    public static Date getYmd(Date date){
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateString = formatter.format(date);
        ParsePosition pos = new ParsePosition(0);
        date = formatter.parse(dateString, pos);
        return date;
    }
    
    /**
     * 获取当前日期，YMD格式
     * @return
     * @author wenping.rong
     */
    public static String getWeek(Date dt){
    	String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        return weekDays[w];
    }
    /**
     * 取得显示时间
     * @return
     */
    public static String getShowTime(){
    	String time = getCurrentTimeString(DATE_FORMATyyyyMMdd_CHN);
    	return time+" "+getWeek(new Date());
    }
    /**
     * 取得显示时间
     * @return
     */
    public static String getShowTime(Date date){
    	String time = getCurrentTimeString(DATE_FORMATyyyyMMdd_CHN,date);
    	return time+" "+getWeek(date);
    }

    /**
     * 获取两个时间相差的小时数
     * @param beginTime
     * @param endTime
     * @return
     */
    public static Float getDiffHours(Date beginTime, Date endTime){
        BigDecimal bg = new BigDecimal((endTime.getTime() - beginTime.getTime()) % nd / nh).setScale(2);
        return  bg.floatValue();
    }
}
